package nina.yiyou.performance.s11collect.compute.score

import nina.yiyou.performance.s11collect.input.CollectFilledReader

import java.util.stream.Stream

import static java.util.stream.Collectors.groupingBy
import static java.util.stream.Collectors.toList
import static java.util.stream.Collectors.toMap

class EvalScoreCalculator {

  EvalScoreCalculator(List<CollectFilledReader.Filler> fillerList) {
    _fillerList = fillerList
  }

  List<Map> calc() {
    // 每个人被其他人评的分数汇总
    Map otherMap = _fillerList.stream()
        .flatMap { getEvalInOthers(it) }
        .collect(groupingBy { GroupScoreCombiner.Group g -> g.evaluateeId() })
        .entrySet().stream()
        .collect(toMap({ Map.Entry e -> e.key }, { Map.Entry e -> makeScoreMap(e.value as List) }))

    // 每个人的自评分数汇总
    Map selfMap = _fillerList.stream().collect(toMap(
        { CollectFilledReader.Filler f -> f.employeeId() },
        { CollectFilledReader.Filler f -> makeSelfScore(f) }))

    return selfMap.entrySet().stream()
        .map { it.value + (otherMap[it.key] ?: [:]) }
        .collect(toList())
  }

  private Stream<GroupScoreCombiner.Group> getEvalInOthers(CollectFilledReader.Filler filler) {
    return _fillerList.stream()
        .map { it.otherEval()[filler.employeeId()] ?: [] }
        .flatMap { new GroupScoreCombiner(it).combine().stream() }
  }

  private Map makeSelfScore(CollectFilledReader.Filler filler) {
    List groupList = new GroupScoreCombiner(filler.selfEval()).combine()
    return ['工号': filler.employeeId()] + makeScoreMap(groupList)
  }

  private Map<String, Double> makeScoreMap(List<GroupScoreCombiner.Group> groupList) {
    def calcScore = { List<GroupScoreCombiner.Group> t ->
      return t.stream()
          .mapToDouble { it.score() }
          .filter { it > 0 } // 回收的表会存在空白没填的列，直接忽略
          .average()
          .orElse(0)
          .round(2)
    }

    return groupList.stream()
        .collect(groupingBy { GroupScoreCombiner.Group g -> "${g.evalType()}_${g.name()}" })
        .entrySet().stream()
        .collect(toMap({ Map.Entry e -> e.key.toString() }, { Map.Entry e -> calcScore.call(e.value as List) }))
  }

  private final List<CollectFilledReader.Filler> _fillerList
}
